```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>异常链(Exception Chaining)详解 | 技术小馆</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css">
    <link rel="stylesheet" href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            color: #333;
            line-height: 1.8;
        }
        h1, h2, h3, h4, .font-serif {
            font-family: 'Noto Serif SC', serif;
            font-weight: 600;
        }
        .hero-gradient {
            background: linear-gradient(135deg, #6e8efb 0%, #a777e3 100%);
        }
        .code-block {
            background: #2d2d2d;
            color: #f8f8f2;
            border-radius: 8px;
            overflow: hidden;
        }
        .code-header {
            background: #1e1e1e;
            padding: 0.5rem 1rem;
            display: flex;
            justify-content: space-between;
            color: #9e9e9e;
        }
        .code-content {
            padding: 1rem;
            overflow-x: auto;
        }
        .card-hover {
            transition: all 0.3s ease;
        }
        .card-hover:hover {
            transform: translateY(-5px);
            box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
        }
        .highlight {
            position: relative;
        }
        .highlight::before {
            content: '';
            position: absolute;
            left: -4px;
            top: 0;
            height: 100%;
            width: 4px;
            background: linear-gradient(to bottom, #6e8efb, #a777e3);
            border-radius: 2px;
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <section class="hero-gradient text-white py-20 px-4 md:px-0">
        <div class="container mx-auto max-w-4xl text-center">
            <i class="fas fa-link text-4xl mb-6 opacity-80"></i>
            <h1 class="text-4xl md:text-5xl font-bold mb-6">异常链(Exception Chaining)</h1>
            <p class="text-xl opacity-90 max-w-2xl mx-auto">
                通过将异常关联起来，为开发者提供完整的错误上下文，让调试和错误处理更高效
            </p>
        </div>
    </section>

    <!-- Main Content -->
    <main class="container mx-auto max-w-4xl px-4 md:px-0 py-16">
        <!-- Introduction -->
        <section class="mb-16">
            <div class="highlight bg-white rounded-lg shadow-md p-8">
                <p class="text-lg leading-relaxed">
                    <span class="text-4xl float-left font-serif mr-3 -mt-2">异</span>
                    <b>异常链(Exception Chaining)</b>是指在处理异常时，通过将一个异常作为另一个异常的原因，以提供更多的上下文信息。这种技术可以帮助开发者更好地了解异常的根本原因，从而更有效地进行调试和错误处理。
                </p>
            </div>
        </section>

        <!-- Working Principle -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <i class="fas fa-cogs mr-3 text-purple-600"></i>
                异常链的工作原理
            </h2>
            <div class="bg-white rounded-lg shadow-md overflow-hidden">
                <div class="p-8">
                    <p class="mb-6">异常链允许一个异常作为另一个异常的"原因"，这样在异常传播的过程中，可以保留原始异常的信息。这对于诊断复杂问题尤其有用，因为它提供了异常发生的完整上下文。</p>
                    
                    <div class="flex justify-center my-8">
                        <div class="mermaid w-full">
                            graph LR
                            A[原始异常] -->|被捕获| B[自定义异常]
                            B -->|抛出| C[调用栈上层]
                            C -->|可能继续| D[...]
                        </div>
                    </div>
                    
                    <div class="grid md:grid-cols-2 gap-6 mt-8">
                        <div class="bg-blue-50 p-6 rounded-lg">
                            <h3 class="font-bold text-lg mb-3 text-blue-800 flex items-center">
                                <i class="fas fa-info-circle mr-2"></i>
                                异常传播
                            </h3>
                            <p>当异常在调用栈中向上传播时，原始异常信息不会丢失，而是被封装在新的异常中。</p>
                        </div>
                        <div class="bg-purple-50 p-6 rounded-lg">
                            <h3 class="font-bold text-lg mb-3 text-purple-800 flex items-center">
                                <i class="fas fa-search mr-2"></i>
                                调试优势
                            </h3>
                            <p>开发者可以追踪完整的异常链，找到问题的根本原因，而不是只看到最后抛出的异常。</p>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Java Implementation -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <i class="fab fa-java mr-3 text-red-500"></i>
                如何在 Java 中实现异常链
            </h2>
            
            <div class="space-y-8">
                <!-- Method 1 -->
                <div class="card-hover bg-white rounded-lg shadow-md overflow-hidden">
                    <div class="p-8">
                        <h3 class="text-2xl font-bold mb-4 flex items-center">
                            <span class="bg-blue-600 text-white rounded-full w-8 h-8 flex items-center justify-center mr-3">1</span>
                            使用构造函数传递异常
                        </h3>
                        <p class="mb-6">Java 的异常类 <code class="bg-gray-100 px-2 py-1 rounded">Throwable</code> 提供了一个构造函数，允许将一个异常对象作为另一个异常的原因传递：</p>
                        
                        <div class="code-block mb-6">
                            <div class="code-header">
                                <span>Java</span>
                                <button class="text-sm"><i class="far fa-copy"></i> 复制</button>
                            </div>
                            <div class="code-content">
                                <pre><code>public class CustomException extends Exception {
    public CustomException(String message, Throwable cause) {
        super(message, cause);
    }
}</code></pre>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Method 2 -->
                <div class="card-hover bg-white rounded-lg shadow-md overflow-hidden">
                    <div class="p-8">
                        <h3 class="text-2xl font-bold mb-4 flex items-center">
                            <span class="bg-purple-600 text-white rounded-full w-8 h-8 flex items-center justify-center mr-3">2</span>
                            在抛出异常时指定原因
                        </h3>
                        <p class="mb-6">在实际使用中，可以在捕获一个异常后，创建一个新的异常并将原始异常作为原因传递给它：</p>
                        
                        <div class="code-block mb-6">
                            <div class="code-header">
                                <span>Java</span>
                                <button class="text-sm"><i class="far fa-copy"></i> 复制</button>
                            </div>
                            <div class="code-content">
                                <pre><code>try {
    // 可能会抛出 IOException 的代码
    someMethod();
} catch (IOException e) {
    throw new CustomException("Failed to process file", e);
}</code></pre>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Method 3 -->
                <div class="card-hover bg-white rounded-lg shadow-md overflow-hidden">
                    <div class="p-8">
                        <h3 class="text-2xl font-bold mb-4 flex items-center">
                            <span class="bg-green-600 text-white rounded-full w-8 h-8 flex items-center justify-center mr-3">3</span>
                            使用 <code>Throwable</code> 的 <code>initCause()</code> 方法
                        </h3>
                        <p class="mb-6"><code>Throwable</code> 类还提供了 <code>initCause()</code> 方法，用于在创建异常对象后设置其原因。不过，这种方法的使用较少，因为在创建异常时直接传递原因更为直观和常见。</p>
                        
                        <div class="code-block mb-6">
                            <div class="code-header">
                                <span>Java</span>
                                <button class="text-sm"><i class="far fa-copy"></i> 复制</button>
                            </div>
                            <div class="code-content">
                                <pre><code>public class CustomException extends Exception {
    public CustomException(String message) {
        super(message);
    }

    public void setCause(Throwable cause) {
        initCause(cause);
    }
}</code></pre>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Complete Example -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <i class="fas fa-code mr-3 text-indigo-600"></i>
                完整示例代码
            </h2>
            
            <div class="bg-white rounded-lg shadow-md overflow-hidden">
                <div class="p-8">
                    <div class="code-block">
                        <div class="code-header">
                            <span>Java</span>
                            <button class="text-sm"><i class="far fa-copy"></i> 复制</button>
                        </div>
                        <div class="code-content">
                            <pre><code>public class Main {
    public static void main(String[] args) {
        try {
            // 调用可能抛出异常的方法
            riskyOperation();
        } catch (IOException e) {
            // 捕获 IOException，并抛出自定义异常，保留原始异常
            throw new CustomException("Custom error message", e);
        }
    }

    private static void riskyOperation() throws IOException {
        // 代码逻辑，可能抛出 IOException
        throw new IOException("Original IO error");
    }
}

class CustomException extends Exception {
    public CustomException(String message, Throwable cause) {
        super(message, cause);
    }
}</code></pre>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Advantages -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <i class="fas fa-star mr-3 text-yellow-500"></i>
                使用异常链的优势
            </h2>
            
            <div class="grid md:grid-cols-3 gap-6">
                <div class="card-hover bg-white p-6 rounded-lg shadow-md">
                    <div class="text-blue-600 text-3xl mb-4">
                        <i class="fas fa-layer-group"></i>
                    </div>
                    <h3 class="font-bold text-xl mb-3">保留异常上下文</h3>
                    <p class="text-gray-700">异常链能够保留原始异常的信息，使得错误信息更加完整和有用。</p>
                </div>
                
                <div class="card-hover bg-white p-6 rounded-lg shadow-md">
                    <div class="text-purple-600 text-3xl mb-4">
                        <i class="fas fa-tools"></i>
                    </div>
                    <h3 class="font-bold text-xl mb-3">提高可维护性</h3>
                    <p class="text-gray-700">开发者可以追踪到异常的根本原因，而不是只看到抛出的异常。</p>
                </div>
                
                <div class="card-hover bg-white p-6 rounded-lg shadow-md">
                    <div class="text-green-600 text-3xl mb-4">
                        <i class="fas fa-bug"></i>
                    </div>
                    <h3 class="font-bold text-xl mb-3">帮助调试</h3>
                    <p class="text-gray-700">通过异常链，可以更容易地找到导致错误的根本原因，从而更快地解决问题。</p>
                </div>
            </div>
        </section>

        <!-- Best Practices -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center">
                <i class="fas fa-lightbulb mr-3 text-yellow-400"></i>
                最佳实践
            </h2>
            
            <div class="bg-white rounded-lg shadow-md overflow-hidden">
                <div class="p-8">
                    <ul class="space-y-4">
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-green-500 mt-1 mr-3"></i>
                            <div>
                                <strong>提供有意义的错误信息</strong>
                                <p class="text-gray-700">自定义异常的消息应该清晰地描述问题，并帮助开发者理解发生了什么。</p>
                            </div>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-green-500 mt-1 mr-3"></i>
                            <div>
                                <strong>不要过度包装异常</strong>
                                <p class="text-gray-700">只有在确实需要添加额外上下文信息时才创建新的异常，避免创建过长的异常链。</p>
                            </div>
                        </li>
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-green-500 mt-1 mr-3"></i>
                            <div>
                                <strong>记录完整异常链</strong>
                                <p class="text-gray-700">在日志中打印异常时，确保打印完整的异常链，而不仅仅是最后一个异常。</p>
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
        </section>
    </main>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-12">
        <div class="container mx-auto max-w-4xl px-4 md:px-0">
            <div class="text-center">
                <h3 class="text-xl font-bold text-white mb-2">技术小馆</h3>
                <p class="mb-6">探索技术之美，分享编程之道</p>
                <a href="http://www.yuque.com/jtostring" class="text-blue-400 hover:text-blue-300 transition-colors" target="_blank">
                    <i class="fas fa-external-link-alt mr-1"></i> www.yuque.com/jtostring
                </a>
            </div>
        </div>
    </footer>

    <script>
        // Initialize Mermaid
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });

        // Add copy functionality to code blocks
        document.querySelectorAll('.code-header button').forEach(button => {
            button.addEventListener('click', () => {
                const code = button.parentElement.nextElementSibling.textContent;
                navigator.clipboard.writeText(code).then(() => {
                    const originalText = button.innerHTML;
                    button.innerHTML = '<i class="fas fa-check"></i> 已复制';
                    setTimeout(() => {
                        button.innerHTML = originalText;
                    }, 2000);
                });
            });
        });
    </script>
</body>
</html>
```